/*****************************************************************************\
Microsoft Research Asia
Copyright (c) Microsoft Corporation. All Rights Reserved.

Module Name:	ImagePos.cpp
Notes:				Implementation of Image Iterator.
History:			Created by Rong Xiao rxiao@microsoft.com		Jun 2, 2006
\*****************************************************************************/
#pragma once

#include "ImageWrapper.h"

#define CIMAGE_SCALE_SHIFTBITS       16
#define CIMAGE_SCALE_FACTOR			((unsigned)(1<<CIMAGE_SCALE_SHIFTBITS))
#define CIMAGE_SCALE_ROUNDBIAS			((unsigned)(1<<(CIMAGE_SCALE_SHIFTBITS-1)))

inline int Double2Int ( double lfValue )
{
	return (int) ( lfValue * CIMAGE_SCALE_FACTOR + 0.5 );
}

class CImagePos
{
protected:
	int m_iIndexX;
	int m_iIndexY;
	unsigned m_uWidth;
	unsigned m_uHeight;
	unsigned m_uDstWidth;
	unsigned m_uDstHeight;
	const CImageWrapper* m_pImage;

	const BYTE * s_GetPixelPtr(int xPos, int yPos) const
	{
		assert (m_pImage);
		if ( xPos>=0 && xPos < (int)m_uWidth && yPos>=0 && yPos<(int)m_uHeight)
		{
			return m_pImage->GetPixelPtr((unsigned)xPos, (unsigned)yPos);
		}
		else
		{
			return 0;
		}
	}

	unsigned s_GetGrayScale(int xPos, int yPos) const
	{
		assert (m_pImage);
		
		if ( xPos>=0 && xPos < (int)m_uWidth && yPos>=0 && yPos<(int)m_uHeight)
		{
			return m_pImage->GetGrayPixel((unsigned)xPos, (unsigned)yPos);
		}
		else
		{
			return 255;
		}	
	}
public:
	CImagePos() : m_pImage(NULL) {};
	
	HRESULT Init ( const CImageWrapper* pImage );
	unsigned GetDstWidth()    const { return m_uDstWidth; }
	unsigned GetDstHeight()   const { return m_uDstHeight; }
	unsigned GetImageWidth () const { return m_uWidth; }
	unsigned GetImageHeight() const { return m_uHeight; }
	void InitIndex (int iIndexX, int iIndexY ) { m_iIndexX=iIndexX; m_iIndexY=iIndexY; }
	void IncIndexX ()  { m_iIndexX++; }
	void IncIndexY ()  { m_iIndexY++; }
	int GetX() const { return m_iIndexX; }
	int GetY() const { return m_iIndexY; }
	unsigned GetGrayScale() const
	{
		assert (m_pImage);
		return m_pImage->GetGrayPixel((unsigned)GetX(), (unsigned)GetY());
	}

	const BYTE * s_GetPixelPtr() const
	{
		return s_GetPixelPtr(GetX(),GetY());
	}

	unsigned s_GetGrayScale() const
	{
		return s_GetGrayScale(GetX(), GetY());
	}
};

class CScaledImagePos : public CImagePos
{
private:
	int m_iScaledSx;
	int m_iScaledSy;
	void InitScaledStep (); 

public:
	HRESULT Init(const CImageWrapper* pImage, unsigned uScaledWidth, unsigned uScaledHeight);
	HRESULT Init(const CImageWrapper* pImage, double dResizeRatio);

	void InitIndex( int iIndexX, int iIndexY ) { m_iIndexX = iIndexX*m_iScaledSx+CIMAGE_SCALE_ROUNDBIAS; m_iIndexY = iIndexY * m_iScaledSy+CIMAGE_SCALE_ROUNDBIAS; };
	void IncIndexX ()  { m_iIndexX+=m_iScaledSx; }
	void IncIndexY ()  { m_iIndexY+=m_iScaledSy; }
	int GetX() const  { return m_iIndexX>>CIMAGE_SCALE_SHIFTBITS; }
	int GetY() const  { return m_iIndexY>>CIMAGE_SCALE_SHIFTBITS; }

	//use new GetX(), GetY()
	const BYTE * s_GetPixelPtr() const
	{
		return CImagePos::s_GetPixelPtr(GetX(),GetY());
	}

	unsigned s_GetGrayScale() const
	{
		return CImagePos::s_GetGrayScale(GetX(), GetY());
	}
	unsigned GetGrayScale() const { return s_GetGrayScale();}
};

class CRotatedImagePos : public CScaledImagePos
{
private:
	int m_iScaledCosSx; 
	int m_iScaledSinSx;
	int m_iScaledCosSy;
	int m_iScaledSinSy;
	int m_iScaledDU;
	int m_iScaledDV;
	int m_iScaledWSrc;
	int m_iScaledHSrc;

	void InitRotatedStep(double dAngle);

public:
	HRESULT Init(const CImageWrapper* pImage, unsigned uScaledWidth, unsigned uScaledHeight, double dAngle);
	HRESULT Init(const CImageWrapper* pImage, double dResizeRatio, double dAngle);

	void InitIndex( int iIndexX, int iIndexY ) 
	{  
		m_iIndexX =  iIndexX * m_iScaledCosSx + iIndexY * m_iScaledSinSy + m_iScaledDU;
		m_iIndexY = -iIndexX * m_iScaledSinSx + iIndexY * m_iScaledCosSy + m_iScaledDV;
	};
	void IncIndexX ()  
	{ 			
		m_iIndexX += m_iScaledCosSx;
		m_iIndexY -= m_iScaledSinSx;
	}
	void IncIndexY ()  
	{			
		m_iIndexX += m_iScaledSinSy;
		m_iIndexY += m_iScaledCosSy; 
	}
	unsigned GetGrayScale() const { return s_GetGrayScale();}
};


